#include "Protocol.hpp"
#include "Socket.hpp"
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
#include <unistd.h>
#include <string>
using namespace std;
using namespace Protocol;
int main(int args, char *argv[])
{
    if (args != 3)
    {
        cout << "Usage:" << argv[0] << " " << "serverip serverport" << endl;
    }
    string serverip = argv[1];
    uint16_t serverport = stoi(argv[2]);
    Net_Work::Socket *coon = new Net_Work::TcpSocket();
    if (!coon->BuildConnectSocketMethod(serverip, serverport))
    {
        std::cerr << "connect " << serverip << ":" << serverport << " failed" << std::endl;
    }
    std::cout << "connect " << serverip << ":" << serverport << " success" << std::endl;
    std::unique_ptr<Factory> factory = std::make_unique<Factory>();
    srand(time(nullptr) ^ getpid());
    string opers = "+-*/%=";
    while (true)
    {
        // 1. 构建一个请求，遵守协议
        int x = rand() % 100;
        usleep(rand() % 7777);
        int y = rand() % 100;
        char oper = opers[rand() % opers.size()];
        std::shared_ptr<Request> req = factory->BuildRequest(x, y,oper);
        // 2. 对请求进行序列化
        string message;
        req->Serialize(&message);
        std::string testreq = message;
        cout<<testreq<<endl;
        testreq += " ";
        testreq += "= ";
        // 3. 添加自描述报头
        string requeststr = Protocol::Encode(message);
        // 4. 发送请求
        coon->Send(requeststr);
        string responsestr;
        while (true)
        {
            // 5. 读取响应
            if (!coon->Recv(&responsestr, 1024))
                break;
            // 6. 报文进行解析
            string response;
            if (!Decode(responsestr, &response))
                continue;
            // 7.response "result code"
            auto resp = factory->BuildResponse();
            resp->Deserialize(response);
            std::cout << testreq << resp->GetResult() << "[" << resp->GetCode() << "]" << std::endl;
            break;
        }
        sleep(1);
    }
    coon->CloseSocket();
    return 0;

}